package com.koron.css2.newProjectCenter.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.koron.css2.ServerInterface;
import com.koron.css2.newProjectCenter.bean.EnterOrOutMaterialBean;
import com.koron.css2.newProjectCenter.bean.PjPubUpMaterial;
import com.koron.css2.newProjectCenter.bean.PjPubUpMaterialVo;
import com.koron.css2.newProjectCenter.bean.PjpubMaterialDocument;
import com.koron.css2.newProjectCenter.bean.query.PjpubMaterialDocumentQuery;
import com.koron.css2.newProjectCenter.mapper.EnterOrOutMaterialMapper;
import com.koron.css2.newProjectCenter.mapper.PjPubUpMaterialMapper;
import com.koron.css2.newProjectCenter.mapper.PjpubMaterialDocumentMapper;
import com.koron.css2.newProjectCenter.mapper.PubUpStoreMapper;
import com.koron.css2.serviceManage.bean.RequestBean;
import com.koron.css2.serviceManage.bean.UserInfoBean;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.util.Constant;
import com.koron.util.Tools;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.swan.bean.MessageBean;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: 苏小龙
 * @CreateTime: 2024-12-04
 * @Description: 材料单据表
 * @Version: 1.0
 */
public class PjPubMaterialDocumentList implements ServerInterface {
    /**
     * 执行与出入库单据相关的操作
     * 根据请求中的 to do 字段决定执行的操作类型：更新或保存、删除、详情查看或列表查询
     *
     * @param factory  用于获取Mapper的SessionFactory
     * @param userInfo 用户信息，用于操作审计
     * @param req      请求Bean，包含操作所需的数据
     * @return 返回操作结果的消息Bean
     */
    @Override
    @Transactional
    public MessageBean<?> exec(SessionFactory factory, UserInfoBean userInfo, RequestBean req) {
        try {
            // 将请求数据转换为查询Bean
            PjpubMaterialDocumentQuery queryBean = JsonUtils.objectToPojo(req.getData(), PjpubMaterialDocumentQuery.class);
            // 获取材料文档的Mapper
            PjpubMaterialDocumentMapper mapper = factory.getMapper(PjpubMaterialDocumentMapper.class);

            // 根据 to do 字段的值决定执行的操作
            if (queryBean.getToDo() != null && queryBean.getToDo() == 2) {
                // 执行更新或保存操作
                return updateOrSave(mapper, factory, userInfo, queryBean);
            }
            if (queryBean.getToDo() != null && queryBean.getToDo() == 3) {
                // 执行删除操作
                return delete(mapper, factory, queryBean);
            }
            if (queryBean.getToDo() != null && queryBean.getToDo() == 4) {
                // 执行详情查看操作
                return getMaterialListByDocId(factory, queryBean.getId());
            }
            if (queryBean.getToDo() != null && queryBean.getToDo() == 5) {
                // 更改状态
                if (queryBean.getId() == null || queryBean.getStatus() == null)
                    return MessageBean.create(Constant.MESSAGE_INT_FAIL, "参数错误", null);
                return updateStatus(mapper, factory, queryBean.getId(), queryBean.getStatus(), queryBean.getWarehouse());
            }

            // 如果 to do 字段为其他值，则执行列表查询操作
            PageHelper.startPage(queryBean.getPage(), queryBean.getPageCount());
            List<PjpubMaterialDocument> pubUpInvoiceList = mapper.getList(queryBean);
            PageInfo<PjpubMaterialDocument> info = new PageInfo<>(pubUpInvoiceList);
            PubUpStoreMapper storeMapper = factory.getMapper(PubUpStoreMapper.class);

            List<PjpubMaterialDocument> result = info.getList().stream().peek(doc -> {
                String storeId = doc.getWarehouse();
                doc.setWarehouseName(storeMapper.selectStoreNameById(storeId));
            }).collect(Collectors.toList());

            info.setList(result);

            // 创建并返回成功消息Bean，包含查询结果
            MessageBean<PageInfo> messageBean = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "操作成功", PageInfo.class);
            messageBean.setData(info);
            return messageBean;
        } catch (Exception e) {
            // 异常处理：记录错误日志并返回失败消息Bean
            logger.error(e.getMessage());
            return MessageBean.create(Constant.MESSAGE_INT_FAIL, "操作失败", null);
        }
    }

    private MessageBean<?> updateStatus(PjpubMaterialDocumentMapper mapper, SessionFactory factory, String id, String status, String storeId) {
        // 出库时对库存量、库存下限进行判断
        if (StringUtils.equalsAnyIgnoreCase(status, Constant.MATERIAL_HAS_EXITED, Constant.MATERIAL_HAS_ENTER, Constant.MATERIAL_HAS_LOST)) {
            if (storeId == null)
                return MessageBean.create(Constant.MESSAGE_INT_FAIL, "请输入仓库信息", null);
            EnterOrOutMaterialMapper enterOrOutMaterialMapper = factory.getMapper(EnterOrOutMaterialMapper.class);
            List<EnterOrOutMaterialBean> materialList = enterOrOutMaterialMapper.getMaterialListByDocId(id);
            PubUpStoreMapper storeMapper = factory.getMapper(PubUpStoreMapper.class);
            if (StringUtils.equalsAnyIgnoreCase(status, Constant.MATERIAL_HAS_EXITED, Constant.MATERIAL_HAS_LOST)) {
                for (EnterOrOutMaterialBean material : materialList) {
                    // 1. 首先判断当前仓库对应材料的库存量是否大于待出库数量
                    // 1.1 获取当前仓库对应材料库存量
                    Integer quantity = storeMapper.getQuantityByStoreIdAndMaterialId(storeId, material.getMaterialId());
                    // 1.2 获取当前材料总库存量
                    Integer totalQuantity = storeMapper.getTotalQuantityByMaterialId(material.getMaterialId());
                    // 1.3 获取当前材料的库存下限
                    Integer lowerLimit = storeMapper.getLowerLimitByMaterialId(material.getMaterialId());
                    // 判断
                    if (quantity < material.getMaterialNum() || totalQuantity - material.getMaterialNum() < lowerLimit) {
                        return MessageBean.create(Constant.MESSAGE_INT_FAIL, "库存不足", null);
                    }
                }
                // 开始执行出库
                materialList.forEach(material -> {
                    storeMapper.updateQuantityByStoreIdAndMaterialId(storeId, material.getMaterialId(), material.getMaterialNum(), false);
                });
            }
            // 入库时对库存上限进行判断
            if (status.equals(Constant.MATERIAL_HAS_ENTER)) {
                for (EnterOrOutMaterialBean material : materialList) {
                    // 1. 首先判断当前仓库对应材料的库存量是否大于待入库数量
                    // 1.2 获取当前材料总库存量
                    Integer totalQuantity = storeMapper.getTotalQuantityByMaterialId(material.getMaterialId());
                    // 1.3 获取当前材料的库存上限
                    Integer upperLimit = storeMapper.getUpperLimitByMaterialId(material.getMaterialId());
                    if (totalQuantity + material.getMaterialNum() > upperLimit && upperLimit > 0) {
                        return MessageBean.create(Constant.MESSAGE_INT_FAIL, "库存已满", null);
                    }
                }
                // 开始执行入库
                materialList.forEach(material ->
                        storeMapper.updateQuantityByStoreIdAndMaterialId(storeId, material.getMaterialId(), material.getMaterialNum(), true)
                );
            }
        }
        int num = mapper.updateStatusById(id, status);
        if (num > 0) {
            return MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "操作成功", null);
        } else {
            return MessageBean.create(Constant.MESSAGE_INT_FAIL, "操作失败", null);
        }
    }


    /**
     * 保存出入库单据信息
     *
     * @param thisMapper 出入库单据映射器，用于执行数据库操作
     * @param factory    Session工厂，用于获取其他Mapper实例
     * @param userInfo   用户信息，包含当前用户详情
     * @param queryBean  封装了出入库单据的相关信息
     * @return 返回一个MessageBean对象，包含操作结果
     */
    private MessageBean<?> updateOrSave(PjpubMaterialDocumentMapper thisMapper, SessionFactory factory, UserInfoBean userInfo, PjpubMaterialDocumentQuery queryBean) {
        int num;
        // 判断是插入还是更新操作
        if (StringUtils.isEmpty(queryBean.getId())) {
            queryBean.setDocNum(Tools.getBillNo(factory, Constant.BILL_NO_ROLE_CODE));
            if (queryBean.getHandlerDate() == null)
                queryBean.setHandlerDate(new Date());
            // 设置创建账号、创建时间和创建人名称
            queryBean.setCreateAccount(userInfo.getUserInfo().getAcount());
            queryBean.setCreateName(userInfo.getUserInfo().getName());
            // 生成唯一ID
            queryBean.setId(Tools.getObjectId());
            // 执行插入操作
            num = thisMapper.insert(queryBean);
        } else {
            // 判断当前单据状态是否已出库或已入库
            PjpubMaterialDocumentQuery single = thisMapper.getSingle(queryBean.getId());
            if (StringUtils.equalsAny(single.getStatus(), Constant.MATERIAL_HAS_EXITED, Constant.MATERIAL_HAS_LOST, Constant.MATERIAL_HAS_ENTER)) {
                return MessageBean.create(Constant.MESSAGE_INT_FAIL, "当前单据已无法修改", null);
            }
            // 设置更新账号、更新时间和更新人名称
            queryBean.setUpdateAccount(userInfo.getUserInfo().getAcount());
            queryBean.setUpdateName(userInfo.getUserInfo().getName());
            // 执行更新操作
            num = thisMapper.update(queryBean);
        }

        // 判断操作是否成功
        if (num > 0) {
            // 获取Mapper实例
            EnterOrOutMaterialMapper enterMapper = factory.getMapper(EnterOrOutMaterialMapper.class);
            // 首先删除所有已有的对应的出入库材料信息
            enterMapper.deleteByDocId(queryBean.getId());
            List<EnterOrOutMaterialBean> enterBeans = queryBean.getEnterOrOutMaterialList();
            if (enterBeans != null && !enterBeans.isEmpty()) {
                for (EnterOrOutMaterialBean ben : enterBeans) {
                    ben.setDocId(queryBean.getId());
                    ben.setCreateInfo(userInfo);
                    // 插入新的出库记录
                    enterMapper.insert(ben);
                }
            } else {
                throw new RuntimeException("材料信息不能为空");
            }
        }

        // 创建并返回操作结果信息
        return MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "操作成功", null);
    }

    private MessageBean<?> delete(PjpubMaterialDocumentMapper mapper, SessionFactory factory, PjpubMaterialDocumentQuery queryBean) {
        // 首先根据出入库单据id删除所有已有的对应的出入库材料信息
        EnterOrOutMaterialMapper enterMapper = factory.getMapper(EnterOrOutMaterialMapper.class);
        enterMapper.deleteByDocId(queryBean.getId());

        // 删除出入库单据
        mapper.deleteById(queryBean.getId());

        return MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "删除成功", null);
    }

    /**
     * 根据文档ID获取材料列表
     *
     * @param factory SessionFactory实例，用于获取数据库映射器
     * @param docId   文档ID，用于查询相关的材料信息
     * @return 返回包含材料列表的MessageBean对象
     */
    private MessageBean<?> getMaterialListByDocId(SessionFactory factory, String docId) {
        // 首先根据出入库单据id获取所有对应的出入库材料的id
        EnterOrOutMaterialMapper mapper = factory.getMapper(EnterOrOutMaterialMapper.class);
        List<EnterOrOutMaterialBean> beans = mapper.getMaterialListByDocId(docId);

        // 根据出入库材料的id获取所有对应的出入库材料的信息
        PjPubUpMaterialMapper materialMapper = factory.getMapper(PjPubUpMaterialMapper.class);
        // 使用Java Stream API对beans集合进行处理，转换每个元素为PjPubUpMaterialVo对象
        List<PjPubUpMaterialVo> materials = beans.stream().map(materialBean -> {
            // 创建一个新的PjPubUpMaterialVo对象
            PjPubUpMaterialVo vo = new PjPubUpMaterialVo();

            // 根据item中的材料ID获取PjPubUpMaterial对象
            PjPubUpMaterial material = materialMapper.getMaterialById(materialBean.getMaterialId());

            // 将material对象的属性值复制到vo对象中
            BeanUtils.copyProperties(material, vo);

            // 设置vo对象的材料ID，这里直接使用vo对象的ID
            vo.setMaterialId(vo.getId());

            // 设置vo对象的材料数量，来源于item对象中的材料数量
            vo.setMaterialNum(materialBean.getMaterialNum());

            // 设置vo对象的备注信息，来源于item对象中的备注信息
            vo.setComments(materialBean.getComments());

            // 返回处理后的vo对象
            return vo;
        }).collect(Collectors.toList());

        // 创建成功查询的消息豆并返回材料列表
        MessageBean<List> info = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "查询成功", List.class);
        info.setData(materials);
        return info;
    }
}
